package com.lightsh.network;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;

public class Response {
	
	public static final int RESPONSE_CODE_OK = 200;
	public static final int RESPONSE_CODE_PASSWORD_INVALID = 403;
	public static final int RESPONSE_CODE_REQUEST_RANGE_ERROR = 416;
	
	public static final String HEADER_KEY_ACCEPT_CODE = "Accept-Encoding";
	public static final String HEADER_ACCEPT_CODE_GZIP = "gzip";
	
    private boolean DEBUG = false;
    private int statusCode; 
    private String responseAsString = null;
    private InputStream is;
    private boolean streamConsumed = false;
    
    /**
     * 创建获取InputStream中数据的结果结构。
     * <br/>注意，这个构造方法会直接从输入流中读取数据并且关闭输入流，后续不能再对输入流进行操作（同时，输入流可能在其他地方被关闭，所以不要在构造方法之外操作它）。
     */
    public Response(int statusCode, InputStream contentStream, String contentEncoding) throws IOException{
    	this.statusCode = statusCode;
    	if(contentEncoding != null && contentEncoding.trim().toLowerCase().equals(HEADER_ACCEPT_CODE_GZIP)){
    		this.is = new GZIPInputStream(contentStream);
    	}else{
    		this.is = contentStream;
    	}
    	// 在这里获取stream的数据，因为该方法之后stream会close掉
    	fetchResponse();
    }
    public Response(String content, int responseCode) {
    	responseAsString = content;
    	statusCode = responseCode;
    }
    
    private void fetchResponse() throws IOException{
    	BufferedReader br;
        try {
            InputStream stream = asStream();
            if (null == stream) {
                return;
            }
            br = new BufferedReader(new InputStreamReader(stream, HttpClient.UTF_8_CODE));
            StringBuffer buf = new StringBuffer();
            String line;
            while (null != (line = br.readLine())) {
                buf.append(line).append("\n");
            }
            this.responseAsString = buf.toString();
            log(responseAsString);
            stream.close();
            streamConsumed = true;
        } catch (NullPointerException npe) {
            // don't remember in which case npe can be thrown
            throw new IOException(npe.getMessage(), npe);
        }
    }

    public int getStatusCode() {
        return statusCode;
    }
    /**
     * Returns the response stream.<br>
     * This method cannot be called after calling asString() or asDcoument()<br>
     * It is suggested to call disconnect() after consuming the stream.
     *
     * Disconnects the internal HttpURLConnection silently.
     * @return response body stream
     * @throws TwitterException
     * @see #disconnect()
     */
    private InputStream asStream() {
        if(streamConsumed){
            throw new IllegalStateException("Stream has already been consumed.");
        }
        return is;
    }

    /**
     * Returns the response body as string.<br>
     * Disconnects the internal HttpURLConnection silently.
     * @return response body
     * @throws TwitterException
     */
    public String asString(){
    	return responseAsString;
    }

    private static Pattern escaped = Pattern.compile("&#([0-9]{3,5});");

    /**
     * Unescape UTF-8 escaped characters to string.
     * @param original The string to be unescaped.
     * @return The unescaped string
     */
    public static String unescape(String original) {
        Matcher mm = escaped.matcher(original);
        StringBuffer unescaped = new StringBuffer();
        while (mm.find()) {
            mm.appendReplacement(unescaped, Character.toString(
                    (char) Integer.parseInt(mm.group(1), 10)));
        }
        mm.appendTail(unescaped);
        return unescaped.toString();
    }

    
    public String toString() {
        if(null != responseAsString){
            return responseAsString;
        }
        return "Response{" +
                "statusCode=" + statusCode +               
                ", responseString='" + responseAsString + '\'' +
                ", is=" + is +
                '}';
    }

    private void log(String message) {
        if (DEBUG) {
            System.out.println("[" + new java.util.Date() + "]" + message);
        }
    }
}
